package logic

import (
	conf "awesome-runner/src/config"
	"awesome-runner/src/logr"
	"awesome-runner/src/queue"
	"awesome-runner/src/sql"
	interactive "awesome-runner/src/ssh"
	"awesome-runner/types"
	"errors"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/RichardKnop/machinery/v2/tasks"
	"github.com/golang-module/carbon"
	"github.com/kataras/iris/v12"
	taskLogrus "github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
)

// 签名验证
func SignatureVerification(ctx iris.Context, crypt types.AbstractCrypt) (int, error) {
	// 签名验证
	crypt.Build()
	crypt.BuildPrefixCryptSign()
	if crypt.Compare() {
		re := regexp.MustCompile(`refs/heads/(.*)`)
		match := re.FindStringSubmatch(crypt.GetCryptDataConfig().Message.Ref)
		var ref string = ""
		if len(match) > 1 {
			ref = match[1]
		}

		logr.Logrus.Printf("当前分支 %s", ref)
		isAllowBranch, err, params := isAllowBranch(crypt.GetCryptDataConfig(), ref)

		if len(match) > 1 && isAllowBranch {
			uuid := logr.SnowFlakeId()
			taskLog, _ := os.Create("runtime/task/" + uuid + ".log")
			defer taskLog.Close()

			taskLogrus.SetOutput(taskLog)

			env, _ := logr.JSON.Marshal(params.Environment)

			eta := time.Now().Add(time.Second * 3)
			args := []tasks.Arg{
				{
					Name:  "UUID",
					Type:  "string",
					Value: uuid,
				},
				{
					Name:  "Symbol",
					Type:  "string",
					Value: crypt.GetCryptDataConfig().Symbol,
				},
				{
					Name:  "Branch",
					Type:  "string",
					Value: ref,
				},
				{
					Name:  "Env",
					Type:  "string",
					Value: string(env),
				},
				{
					Name:  "BeforeScript",
					Type:  "[]string",
					Value: params.BeforeScript,
				},
				{
					Name:  "Script",
					Type:  "[]string",
					Value: params.Script,
				},
				{
					Name:  "AfterScript",
					Type:  "[]string",
					Value: params.AfterScript,
				},
			}
			// 发送部署任务
			signature := &tasks.Signature{
				UUID: uuid,
				Name: "call",
				Args: args,
				ETA:  &eta,
				// 重试次数和斐波那契间隔
				// RetryCount:   3,
				// RetryTimeout: 15,
			}

			argsString, _ := logr.JSON.Marshal(args)
			tl := types.TaskLog{
				Symbol:    crypt.GetCryptDataConfig().InternalDeloy.Symbol,
				Committer: crypt.GetCryptDataConfig().Message.UserName,
				Version:   string([]byte(crypt.GetCryptDataConfig().Message.After)[:7]),
				Uuid:      uuid,
				CreateAt:  carbon.Now().ToTimestamp(),
				Args:      string(argsString),
				Type:      1,
			}

			if _, err := queue.MachineryServer.SendTask(signature); err != nil {
				tl.State = "FAILURE"
				sql.GetLiteInstance().Create(&tl)

				taskLogrus.Errorf("Failed task delivered，%v", err)
				logr.Clog.Errorf("Failed task delivered，%v", err)
			} else {
				tl.State = "PENDING"
				sql.GetLiteInstance().Create(&tl)

				return ctx.JSON(types.Response{
					Code:    200,
					Message: "Success task " + uuid + " delivered",
					Data:    nil,
				})
			}
		}

		if !isAllowBranch {
			return ctx.JSON(types.Response{
				Code:    400,
				Message: err.Error(),
				Data:    nil,
			})
		}
	}

	return ctx.JSON(types.Response{
		Code:    400,
		Message: "Invalid signature",
		Data:    nil,
	})
}

// 判断是否分支是否需要发布
func isAllowBranch(crypt types.CryptDataConfig, ref string) (bool, error, types.TaskParams) {
	// 链接ssh
	sshHost := crypt.Project.Auth.Host
	sshUser := crypt.Project.Auth.User
	sshPassword := crypt.Project.Auth.Pwd
	sshType := "password"       //password 或者 key
	sshKeyPath := "id_rsa path" //ssh id_rsa.id 路径"
	sshPort := crypt.Project.Auth.Port

	//创建ssh登陆配置
	config := &ssh.ClientConfig{
		Timeout:         time.Second * 5,
		User:            sshUser,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}
	if sshType == "password" {
		config.Auth = []ssh.AuthMethod{ssh.Password(sshPassword)}
	} else {
		config.Auth = []ssh.AuthMethod{interactive.PublicKeyAuthFunc(sshKeyPath)}
	}

	//dial 获取ssh client
	addr := fmt.Sprintf("%s:%d", sshHost, sshPort)
	sshClient, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		logr.Clog.Errorf("创建ssh client 失败, %v", err)
		return false, err, types.TaskParams{}
	}
	defer sshClient.Close()

	snowflake := carbon.Now().Format("Ymd") + logr.SnowFlakeId()
	var content string
	u, err := url.Parse(crypt.Message.Repository.HtmlUrl)
	if err != nil {
		return false, errors.New(fmt.Sprintf("仓库地址解析失败：%v", crypt.Message.Repository.HtmlUrl)), types.TaskParams{}
	}
	if crypt.Platform == 3 {
		// gitlab
		// crypt.InternalDeloy.ProjectId
		// crypt.InternalDeloy.Token
		// http://repository.yindadianzi.com/api/v4/projects/12/repository/files/.runner-ci.yml/raw?ref=prod&private_token=8Yfmt5mu_DwXyM1Xum8H

		requestUrl := fmt.Sprintf("%s://%s/api/v4/projects/%d/repository/files/.runner-ci.yml/raw?ref=%s", u.Scheme, u.Hostname(), crypt.InternalDeloy.ProjectId, ref)
		response, err := logr.RequestGet(requestUrl, types.RequestHeader{
			Name:  "PRIVATE-TOKEN",
			Value: crypt.InternalDeloy.Token,
		}, false)
		if err != nil {
			return false, err, types.TaskParams{}
		}
		content = response
	} else if crypt.Platform == 2 {
		// gitee 需要decode
		// base64.StdEncoding.DecodeString()
		// https://gitee.com/api/v5/repos/marksirl/go-runner/contents/.runner-ci.yml?access_token=cb2aebbcd7449f7e25bc950ccf1b0106&ref=master
		//repo := strings.Split(u.Path, "/")[1]
		//pojoName := strings.Trim(strings.Split(u.Path, "/")[2], ".git")
	} else if crypt.Platform == 1 {
		// github 需要decode
		// base64.StdEncoding.DecodeString()
		// https://api.github.com/repos/zrone/JDproject/contents/.gitignore?ref=master
		//repo := strings.Split(u.Path, "/")[1]
		//pojoName := strings.Trim(strings.Split(u.Path, "/")[2], ".git")
	} else {
		logr.Clog.Errorf("暂不支持的平台类型, %v", crypt.Platform)
		return false, err, types.TaskParams{}
	}

	dir, _ := os.Getwd()
	cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf(`touch %s/runtime/git/%s.runner-ci.yml`, dir, snowflake))
	cmd.Start()
	cmd.Wait()

	// 内容写入文件
	f, err := os.OpenFile(fmt.Sprintf("%s/runtime/git/%s.runner-ci.yml", dir, snowflake), os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		logr.Clog.Errorf("open file error :", err)
		return false, err, types.TaskParams{}
	}
	// 关闭文件
	defer f.Close()
	_, err = f.WriteString(content)
	if err != nil {
		logr.Clog.Errorf("文件写入失败 :", err)
		return false, err, types.TaskParams{}
	}
	var (
		runnerCi types.RunnerCi
	)
	// 解析部署脚本
	conf.ParseYaml(fmt.Sprintf("runtime/git/%s.runner-ci.yml", snowflake), &runnerCi)
	var (
		isContain bool             = false
		taskParam types.TaskParams = types.TaskParams{
			Environment:  runnerCi.Environment,
			BeforeScript: runnerCi.Prepare,
			Script:       runnerCi.Script,
			AfterScript:  runnerCi.Release,
		}
	)
	fmt.Println(runnerCi.Only)
	for _, b := range runnerCi.Only {
		if strings.Compare(b, ref) == 0 {
			isContain = true
			break
		}
	}

	err = nil
	if !isContain {
		err = errors.New("不允许的构建分支")
	}

	return isContain, err, taskParam
}
